package com.biz.primus.ms.commodity.service.backend;

import com.biz.primus.base.enums.vendor.VendorType;
import com.biz.primus.base.exception.BizParameterException;
import com.biz.primus.base.exception.BizSilentException;
import com.biz.primus.base.vo.GeoLevel;
import com.biz.primus.base.vo.commodity.ProductIdxIdentityVo;
import com.biz.primus.base.vo.commodity.SaleStatus;
import com.biz.primus.commodity.enums.ProductAuditStatus;
import com.biz.primus.commodity.exception.CommodityExceptionType;
import com.biz.primus.commodity.vo.backend.*;
import com.biz.primus.common.utils.JsonUtil;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.vendor.vo.VendorVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.commodity.dao.po.*;
import com.biz.primus.ms.commodity.dao.redis.ProductRedisDao;
import com.biz.primus.ms.commodity.dao.repository.brand.BrandRepository;
import com.biz.primus.ms.commodity.dao.repository.category.CategoryRepository;
import com.biz.primus.ms.commodity.dao.repository.product.GeoProductRepository;
import com.biz.primus.ms.commodity.dao.repository.product.ProductAuditRepository;
import com.biz.primus.ms.commodity.dao.repository.product.ProductRepository;
import com.biz.primus.ms.commodity.dao.specification.GeoProductSpecification;
import com.biz.primus.ms.commodity.dao.specification.ListVendorRelevanceProductSpecification;
import com.biz.primus.ms.commodity.dao.specification.ProductAuditNotPassSpecification;
import com.biz.primus.ms.commodity.dao.specification.ProductListSpecification;
import com.biz.primus.ms.commodity.event.*;
import com.biz.primus.ms.commodity.feign.PriceFeignClient;
import com.biz.primus.ms.commodity.feign.StockFeignClient;
import com.biz.primus.ms.commodity.feign.VendorFeignClient;
import com.biz.primus.ms.commodity.trans.*;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;

/**
 * 商品 Service(平台后台用)
 *
 * @author david-liu
 * @date 2016年12月19日
 * @reviewer
 * @see
 */
@Slf4j
@Service
public class VendorProductService extends AbstractBaseService {

    private static final long serialVersionUID = -8626682761820728820L;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ProductAuditRepository productAuditRepository;

    @Autowired
    private BrandRepository brandRepository;

    @Autowired
    private CategoryRepository categoryRepository;

    @Autowired
    private GeoProductRepository geoProductRepository;

    @Autowired
    private StockFeignClient stockService;

    @Autowired
    private PriceFeignClient priceService;

    @Autowired
    private ProductRedisDao productRedisDao;

//    todo:nan
//    @Autowired
//    private MessageService messageService;

    @Autowired
    private VendorFeignClient vendorRepository;

    @Transactional
    public CreateProductAuditVo createAuditProduct(CreateProductAuditVo vo) {
        ProductAudit productAudit = this.createOrUpdateProductAudit(vo, Boolean.TRUE);
        if (log.isDebugEnabled()) {
            log.debug("productAudit: {}", productAudit.toString());
        }
        productAudit = productAuditRepository.save(productAudit);
        if (log.isDebugEnabled()) {
            log.debug("po after save: {}", productAudit.toString());
        }
        vo.setId(productAudit.getId());
        publishEvent(new VendorCreateProductEvent(this));
        return vo;
    }

    @Transactional
    public void updateAuditProduct(UpdateProductAuditVo vo) {
        ProductAudit productAudit = this.createOrUpdateProductAudit(vo, Boolean.FALSE);
        productAudit = productAuditRepository.save(productAudit);

        if (log.isDebugEnabled()) {
            log.debug("po after save: {}", productAudit.toString());
        }

        publishEvent(new VendorUpdateProductEvent(this));
    }

    public SpringPageVO<VendorProductListItemVo> listVendorProducts(VendorProductListReqVo reqVo) {
        if (reqVo.getSearchPageVo() != null && reqVo.getSearchPageVo().getPageSize() < 1){
            reqVo.getSearchPageVo().setPageSize(10);
        }
        if (reqVo.getSearchPageVo() != null && reqVo.getSearchPageVo().getPageIndex() < 1){
            reqVo.getSearchPageVo().setPageIndex(1);
        }
        return this.findVendorProducts(reqVo);
    }


    public SpringPageVO<VendorDeletedProductListItemVo> listVendorDeletedProducts(VendorProductListReqVo reqVo) {
        return this.findDeletedProducts(reqVo);
    }

    public VendorProductDetailVo getVendorProductDetail(Long vendorId, Long productId) {
        if (vendorId == null || productId == null) {
            throw new BizParameterException("vendorId或者productId不能为空");
        }

        Product product = productRepository.findByIdAndVendorIdAndDeleteFlag(productId,vendorId, Boolean.FALSE);
        if (product == null) {
            throw new BizSilentException(CommodityExceptionType.PRODUCT_NOT_FOUND,"该商品不存在或者已删除");
        }
        VendorProductDetailVo vo = new Product2VendorProductDetailVo().apply(product);
        // TODO 设置商户名称, 设置商品扩展属性
        return vo;
    }

    public VendorProductAuditDetailVo getVendorProductAuditDetail(Long vendorId, Long productId) {
        if (vendorId == null || productId == null) {
            throw new BizParameterException("vendorId或者productAuditId不能为空");
        }


        ProductAudit productAudit = productAuditRepository.findByProductIdAndVendorIdAndDeleteFlag(productId, vendorId, Boolean.FALSE);
        VendorProductAuditDetailVo vo = new ProductAudit2VendorProductAuditDetailVo().apply(productAudit);
        // TODO 设置商户名称, 设置商品扩展属性
        return vo;
    }


    private void updateGeoProduct(PutAwayVo putAwayVo, GeoProduct geoProduct) {
        ProductAudit productAudit = productAuditRepository.findByProductIdAndDeleteFlag(Long.valueOf(putAwayVo.getProductId()), Boolean.FALSE);
        Product product = productRepository.findByIdAndVendorId(Long.valueOf(putAwayVo.getProductId()), putAwayVo.getVendorId());
        if (productAudit == null) {
            throw new RuntimeException("商品审核记录不存在");
        }
        if (product == null) {
            throw new RuntimeException("product不存在");
        }
        geoProduct.setProduct(product);
        geoProduct.setProductAudit(productAudit);
        geoProduct.setLimitPrice(putAwayVo.getMinPrice());
        geoProduct.setMarketPrice(new BigDecimal(putAwayVo.getMarketPrice()).multiply( new BigDecimal(100)).intValue());
        geoProduct.setSalePrice(new BigDecimal(putAwayVo.getFinalPrice()).multiply( new BigDecimal(100)).intValue());
        geoProduct.setVendorId(product.getVendorId());
    }

    private GeoProduct createGeoProduct(PutAwayVo putAwayVo) {
        ProductAudit productAudit = productAuditRepository.findByProductIdAndDeleteFlag(Long.valueOf(putAwayVo.getProductId()), Boolean.FALSE);
        if (productAudit == null) {
            throw new RuntimeException("商品审核记录不存在");
        }
        Product product = productRepository.findByIdAndVendorId(Long.valueOf(putAwayVo.getProductId()), putAwayVo.getVendorId());
        if (product == null) {
            throw new RuntimeException("product不存在");
        }
        GeoProduct geoProduct = new GeoProduct();
        geoProduct.setId(idService.getNextId());
        geoProduct.setGeoLevel(GeoLevel.GEO_CITY);
        geoProduct.setLimitPrice(putAwayVo.getMinPrice());
        geoProduct.setMarketPrice(Integer.valueOf(putAwayVo.getMarketPrice()));
        geoProduct.setSalePrice(Integer.valueOf(putAwayVo.getFinalPrice()));
        geoProduct.setProduct(product);
        geoProduct.setProductAudit(productAudit);
        geoProduct.setVendorId(product.getVendorId());
        geoProduct.setOnSaleTimestamp(new Timestamp(System.currentTimeMillis()));
        return geoProduct;
    }


    /**
     * 商品下架(A类)
     * 1.查找下架商品的geoProduct
     * 2.设置geoProduct为下架状态
     * 3.调用增量索引,同步商品信息
     *
     */
    @Transactional
    public void soldOutProduct(SoldOutProductVo soldOutProductVo) {
        log.info("下架商品请求vo {}",soldOutProductVo);
        if(StringUtils.isEmpty(soldOutProductVo.getProductId())){
            throw new IllegalArgumentException("商品id不能为空");
        }
        ProductAudit productAudit = productAuditRepository.findByProductIdAndDeleteFlag(Long.valueOf(soldOutProductVo.getProductId()), Boolean.FALSE);
        if (productAudit == null){
            throw new BizSilentException("找不到商品审核数据");
        }
        GeoProduct geoProduct = geoProductRepository.findByProductIdAndVendorId(productAudit.getProductId(), productAudit.getVendorId());
        if (geoProduct == null) {
            throw new BizSilentException("无该商品的Geo信息");
        }
        geoProduct.setSaleStatus(SaleStatus.OFF_SALE);
        log.info("开始下架商品 [{}]", JsonUtil.obj2Json(geoProduct.toProductRo()));
        GeoProduct save = geoProductRepository.save(geoProduct);
        log.info("商品状态为 --》  {}",save.getSaleStatus().getDescription());

        log.info("发送下架事件");
        VendorSoldOutProductEvent event = new VendorSoldOutProductEvent(this, geoProduct);
        this.publishEvent(event);

        ProductIdxIdentityVo productIdxIdentityVo = new ProductIdxIdentityVo();
        productIdxIdentityVo.setProductCode(productRepository.findProductCodeById(productAudit.getProductId()));
        if(StringUtils.isBlank(productIdxIdentityVo.getProductCode())){
            throw new RuntimeException("商品不存在");
        }
        productIdxIdentityVo.setWillBeDeleted(true);
        productIdxIdentityVo.setSaleStatus(SaleStatus.OFF_SALE);
        productIdxIdentityVo.setProductType(VendorType.TYPE_A.getValue());
        log.info("调用增量索引");
//        messageService.sendMessage(BizBaseQueue.MQ_SEARCH_PRODUCT_QUEUE, SimpleBizMessage.newMessage(productIdxIdentityVo));
        log.info("下架操作完成");
    }

    public void canPutAway(Long geoProductId, GeoProduct geoProduct) {
        if (geoProduct == null) {
            throw new BizSilentException("无该商品的Geo信息");
        }
        ProductAudit auditProduct = productAuditRepository.findByProductIdAndDeleteFlag(geoProductId, Boolean.FALSE);
        if (auditProduct == null) {
            throw new BizSilentException("无该商品的审核记录");
        }
        if (auditProduct.getAuditStatus() != ProductAuditStatus.PASS) {
            throw new BizSilentException("商品未通过审核");
        }
    }

    /**
     * 商家端后台获取关联商品信息
     * <p>
     * 1.通过productCode,在redis中获取该商品的关联商品信息
     * 2.组装respVo,返回
     *
     */
    public RelevanceProductVo getRelevanceProduct(SearchRelevanceProductVo reqVo) {
        List<String> relevanceList = productRedisDao.findRelevanceList(reqVo.getProductCode());
        List<Product> relevanceProducts = productRepository.findByProductCodeInAndVendorId(relevanceList,reqVo.getVendorId());
        Product targetProduct = productRepository.findByProductCode(reqVo.getProductCode());
        if (targetProduct == null){
            throw new BizSilentException("productNotFound in DB");
        }
        RelevanceProductVo respVo = new RelevanceProductVo();
        respVo.setProductName(targetProduct.getName());
//        respVo.setCategoryName(targetProduct.getCategory().getName());
        respVo.setLogo(targetProduct.getLogo());
        respVo.setProductCode(targetProduct.getProductCode());
        List<RelevanceProductVo> list = Lists.newArrayList();
        for (Product index:relevanceProducts){
            RelevanceProductVo tmpVo = new RelevanceProductVo();
            tmpVo.setProductName(index.getName());
//            tmpVo.setCategoryName(index.getCategory().getName());
            tmpVo.setLogo(index.getLogo());
            tmpVo.setProductCode(index.getProductCode());
            list.add(tmpVo);
        }
        respVo.setRelevanceProductVos(list);
        return respVo;
    }

    /**
     * 获取vendor关联商品的列表
     * 1.通过vendorId在redis中查找该vendorId下关联商品配置项
     * 2.组装
     *
     */
    public SpringPageVO<ListRelevanceProductVo> listVendorRelevanceProduct(ListVendorRelevanceProductReqVo reqVo) {
        SearchPageVo searchPageVo = reqVo.getSearchPageVo();
        if (searchPageVo == null) {
            throw new BizParameterException("页面分页对象错误");
        }
        Page<Product> products = productRepository.findAll(new ListVendorRelevanceProductSpecification(reqVo),
                new PageRequest(searchPageVo.getPageIndex(), searchPageVo.getPageSize()));
        return SpringPageToSpringPageVO.of(products,new Product2ListRelevanceProductVo(geoProductRepository));
    }

    public SpringPageVO<ProductBriefVo> getVendorProductList(BackendProductListReqVo reqVo) throws BizParameterException {
        if (reqVo.getSearchPageVo() == null) {
            throw new BizParameterException("分页对象不能为空");
        }
        PageRequest pageRequest = new PageRequest(reqVo.getSearchPageVo().getPageIndex(), reqVo.getSearchPageVo().getPageSize());
        Page<Product> page = productRepository.findAll(new ProductListSpecification(reqVo), pageRequest);
       return SpringPageToSpringPageVO.of(page,new Product2ProductBriefVo());
    }

    public List<ProductLogoVo> getProductLogoList(ProductLogoReqVo productLogoReqVo) {
        List<Product> products = productRepository.findByIdInAndVendorId(productLogoReqVo.getProductId(), productLogoReqVo.getVendorId());
        List<ProductLogoVo> respVo = Lists.newArrayList();
        for (Product product : products) {
            ProductLogoVo productLogoVo = new ProductLogoVo(product.getProductCode(), product.getLogo(), product.getName());
            respVo.add(productLogoVo);
        }
        return respVo;
    }

    public void closeDepotSoldOutAllProducts() {

    }

    /**
     * 根据 Vo 创建或者更新商品审核 Po
     *
     * @param vo vo
     * @param isCreate 创建标识
     * @return 商品审核 Po
     */

    private ProductAudit createOrUpdateProductAudit(IProductAuditVo vo, Boolean isCreate) {
        if (log.isDebugEnabled()) {
            log.debug("vo: {}", vo.toString());
        }
        Long brandId = vo.getBrandId();
        Long categoryId = vo.getCategoryId();
        if (brandId == null || categoryId == null) {
            log.error("商品品牌 ID 和商品分类 ID 不能为空, brandId=[{}], categoryId=[{}]", brandId, categoryId);
            throw new BizParameterException("商品品牌 ID 和商品分类 ID 不能为空");
        }

        VendorVo vendor = vendorRepository.findOne(vo.getVendorId());
        if (vendor == null){
            throw new BizParameterException("该vendor不存在");
        }

        // 根据创建标识创建或者查找商品审核 Po
        ProductAudit productAudit;
        if (isCreate == null || !isCreate) {
            productAudit = productAuditRepository.findByIdAndDeleteFlag(vo.getId(), Boolean.FALSE);
            // 如果没查找到商品审核 Po, 抛出异常
            if (productAudit == null) {
                log.error("商品ID不能为空");
                throw new BizSilentException("该商品的商品审核记录未找到");
            }
        } else {
            // 如果为新创建记录, 创建商品审核 Po(id 自增) 并且生成商品 Id
            productAudit = new ProductAudit();
            productAudit.setId(idService.getNextId());
            productAudit.setVendorId(vo.getVendorId());
            productAudit.setProductId(idService.getNextId());
            productAudit.setProductCode(String.valueOf(idService.getNextId()));
        }

        // 从 Vo 复制属性到 Po
        productAudit.fromVo(vo);
        productAudit.setVendorName(vendor.getVendorName());
        // 取品牌和分类
        Brand brand = brandRepository.findByIdAndDeleteFlag(brandId, Boolean.FALSE);
        Category category = categoryRepository.findByIdAndDeleteFlag(categoryId, Boolean.FALSE);

        // 设置分类, 如果分类为空抛出异常
        if (category == null) {
            throw new BizSilentException("该商品对应的分类不存在或者已删除");
        } else {
            productAudit.setCategory(category);
        }

        // 设置品牌, 如果品牌为空抛出异常
        if (brand == null) {
            throw new BizSilentException("该商品对应的品牌不存在或者已删除");
        } else {
            productAudit.setBrand(brand);
        }

        // 设置商品扩展属性

        if (isCreate == null || !isCreate) {
            // 如果为编辑商品操作
            Long productId = productAudit.getProductId();
            Long vendorId = productAudit.getVendorId();
            Product product = productRepository.findByIdAndVendorId(productId, vendorId);
            log.debug("排除首次申请被拒 无product的情况");
            if (product != null) {
                if (product.getLocked()) {
                    throw new BizSilentException("该商品已经锁定, 不能更改该商品");
                }
                log.debug("更新product的inAudit字段");
                product.setInAudit(Boolean.TRUE);
            } else {
                log.info("没有查到product");
            }


            if (productAudit.getAuditStatus() == ProductAuditStatus.INIT) {
                // 之前新建审核记录, 不做审核状态改变
            } else if (productAudit.getAuditStatus() == ProductAuditStatus.INIT_DENY) {
                // 新建审核记录被拒绝, 更改审核状态为新建审核状态
                productAudit.setAuditStatus(ProductAuditStatus.INIT);
            } else if (productAudit.getAuditStatus() == ProductAuditStatus.MODIFIED) {
                // 已修改状态, 不做审核状态改变
            } else if (productAudit.getAuditStatus() == ProductAuditStatus.MODIFY_DENY) {
                // 修改被拒绝状态, 状态更改为已修改
                productAudit.setAuditStatus(ProductAuditStatus.MODIFIED);
            } else {
                // 之前为审核通过状态, 修改状态为已修改
                productAudit.setAuditStatus(ProductAuditStatus.MODIFIED);
            }
        } else {
            // 设置待审核商品记录为初始化提交状态
            productAudit.setAuditStatus(ProductAuditStatus.INIT);
        }
        return productAudit;
    }

    private SpringPageVO<VendorProductListItemVo> findVendorProducts(VendorProductListReqVo reqVo)
            throws BizParameterException {
        SearchPageVo searchPageVo = reqVo.getSearchPageVo();
        if (searchPageVo == null) {
            throw new BizParameterException("页面分页对象错误");
        }
        if(reqVo.getAuditStatus() == ProductAuditStatus.PASS){
            log.debug("审核通过的商品列表");
            return this.findAuditPassProduct(reqVo, searchPageVo);
        } else {
            log.debug("查询审核不通过且未上架的商品列表");
            return this.findAuditNotPassProduct(reqVo,searchPageVo);
        }

    }

    private SpringPageVO<VendorProductListItemVo> findAuditNotPassProduct(VendorProductListReqVo reqVo, SearchPageVo searchPageVo) {
//        从auditProduct 中查询审核状态不通过的。
        Page<ProductAudit> productAudits = productAuditRepository.findAll(new ProductAuditNotPassSpecification(reqVo),
                new PageRequest(searchPageVo.getPageIndex(), searchPageVo.getPageSize()));
        return SpringPageToSpringPageVO.of(productAudits,new ProductAudit2VendorProductListItemVo());
    }

    private SpringPageVO<VendorProductListItemVo> findAuditPassProduct(VendorProductListReqVo reqVo, SearchPageVo searchPageVo) {
        Page<GeoProduct> geoProducts = geoProductRepository.findAll(new GeoProductSpecification(reqVo),
                new PageRequest(searchPageVo.getPageIndex(), searchPageVo.getPageSize()));
        return SpringPageToSpringPageVO.of(geoProducts,new GeoProduct2VendorProductListItemVo());
    }

    private List<String> getListGeoProductCode(List<GeoProduct> geoProducts){
        List<String> productCodeList = Lists.newArrayList();
        for (GeoProduct geoProduct:geoProducts){
            productCodeList.add(geoProduct.getProduct().getProductCode());
        }
        return productCodeList;
    }

    private SpringPageVO<VendorDeletedProductListItemVo> findDeletedProducts
            (VendorProductListReqVo reqVo) throws BizParameterException {
        SearchPageVo searchPageVo = reqVo.getSearchPageVo();
        if (searchPageVo == null) {
            throw new BizParameterException("页面分页对象错误");
        }
        PageRequest pageRequest = new PageRequest(searchPageVo.getPageIndex(), searchPageVo.getPageSize());
        Page<Product> products = productRepository.findByVendorIdAndDeleteFlag(reqVo.getVendorId(), Boolean.TRUE, pageRequest);
        return SpringPageToSpringPageVO.of(products, new Product2VendorDeletedProductListItemVo());
    }
}
